package com.may.wlrj.crypto;

import java.io.UnsupportedEncodingException;

import javax.annotation.PostConstruct;

import org.springframework.stereotype.Component;

import com.sun.jna.Memory;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
import com.sun.jna.ptr.ByteByReference;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.ptr.PointerByReference;

@Component
public class GXUSBUtil {
	public static GXUSBUtil gxUSBUtil;
	private PointerByReference phKey = new PointerByReference(Pointer.NULL);
	private GXUSBKeyAbs instanceDll = null;
	private BLOCKCIPHERPARAM bp = null;
	private final byte[] wlkey = {0x30,0x71,0x55,0x30,0x71,0x44,0x71,0x55,0x30,0x71,0x30,0x71,0x56,0x30,0x71,0x43};
	
	@PostConstruct
    public void init() {    
		gxUSBUtil = this;
    } 
    
	public void initJnaGX() {
    	String webRootPath = GXUSBUtil.class.getResource("").getPath().replaceFirst("/", "");
    	String webInfPath = webRootPath.substring(0,webRootPath.indexOf("classes"));
    	String dllpath = webInfPath + "SKFDLL";
    	instanceDll  = (GXUSBKeyAbs)Native.loadLibrary(dllpath,GXUSBKeyAbs.class);
    	byte[] szNameList = new byte[1024];
    	IntByReference pulSize = new IntByReference(1024);
    	Pointer phDev;
    	PointerByReference devhandle = new PointerByReference(Pointer.NULL);
    	
    	int res = instanceDll.SKF_EnumDev(true, szNameList, pulSize);
    	try {
			String val = new String(szNameList,"utf-8");
			res = instanceDll.SKF_ConnectDev(szNameList, devhandle);
			phDev = devhandle.getValue();
			res = instanceDll.SKF_SetSymmKey(phDev, wlkey, 0x00000401, phKey);
			bp = new BLOCKCIPHERPARAM();
			bp.IV = wlkey;
			bp.FeedBitLen = 0;
			bp.IVLen = 16; 
			bp.PaddingType = 0;
			//测试SM4加密解密
			IntByReference pulEncrypedLen = new IntByReference(1024);
			byte[] encrydata = new byte[1024];
			String testval = "prevailwlhznixinlongliyinjinyinlong";
			byte[] testvalbytes = testval.getBytes();
			//开始加密
			res = instanceDll.SKF_EncryptInit(phKey.getValue(),bp);
			int len = testvalbytes.length;
			res = instanceDll.SKF_EncryptUpdate(phKey.getValue(), testvalbytes, 128, encrydata, pulEncrypedLen);
			if(pulEncrypedLen.getValue() > 0) {
				System.out.println("----pulEncrypedLen=" + pulEncrypedLen.getValue());
			}			
			int enclen = pulEncrypedLen.getValue();
			
			pulEncrypedLen.setValue(1024);			
			res = instanceDll.SKF_EncryptFinal(phKey.getValue(), null , pulEncrypedLen);
			//res = instanceDll.SoftSM4_Crypto(0x00000401,true,testval.getBytes(),testvalbytes.length,wlkey,wlkey,encrydata,pulEncrypedLen);
			enclen += pulEncrypedLen.getValue();
			//加密结束
			System.out.println("----pulEncrypedLen=" + pulEncrypedLen.getValue());
			
			//开始同步解密，还原明文
			IntByReference pulDecrypedLen = new IntByReference(1024);
			byte[] decrydata = new byte[1024];
			res = instanceDll.SKF_DecryptInit(phKey.getValue(),bp);
			
			res = instanceDll.SKF_DecryptUpdate(phKey.getValue(), encrydata, 128, decrydata, pulDecrypedLen);
			if(pulDecrypedLen.getValue() > 0) {
				System.out.println("----pulDecrypedLen=" + pulDecrypedLen.getValue());
			}
			int declen = pulDecrypedLen.getValue();
			pulDecrypedLen.setValue(1024);
			res = instanceDll.SKF_DecryptFinal(phKey.getValue(), null, pulDecrypedLen);
			//res = instanceDll.SoftSM4_Crypto(0x00000401,false,encrydata,pulEncrypedLen.getValue(),wlkey,wlkey,decrydata,pulDecrypedLen);
			declen += pulDecrypedLen.getValue();
			//解密结束
			System.out.println("----pulDecrypedLen=" + declen);
			System.out.println("----decrydata=" + new String(decrydata).substring(0, 35));
			//明文导入会话密钥
			//GXUSBENDE(instanceDll,phDev);
			
			//byte[] xxx = this.GXUSBKeyEncrypt("prevail");
			//System.out.println(new String(xxx, "utf-8"));
		} catch (UnsupportedEncodingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
    	
	}
	
	public void GXUSBENDE(GXUSBKeyAbs instanceDll,Pointer phDev) {
		int algo = 0x00000401;  //SM4 算法 ECB 加密模式

		byte[] key = new byte[32];
		for(int i=0;i<32;i++)
		{
			key[i]=1;
		}
		bp = new BLOCKCIPHERPARAM();

		int ret = 0;
		
		ret = instanceDll.SKF_SetSymmKey(phDev, key, algo, phKey);
		if(ret != 0) {
			System.out.println("导入明文密钥失败=====" + Integer.toHexString(ret));
		}
		
		bp.FeedBitLen = 0;
		bp.IVLen = 0; 
        //instanceDll.SKF_CloseHandle(phKey.getValue());
        
	}
	
	/*public byte[] GXUSBKeyEncrypt(String mdata) {
		byte[] data = mdata.getBytes();
		int data_len = (data.length - 1) * 8;
		int encrypt_data_len = data_len + 1024;
		Pointer encrypt_data = new Memory(1024);
		IntByReference pulEncrypedLen = new IntByReference();
		pulEncrypedLen.setValue(encrypt_data_len);
		int ret = 0;
		//加密
		ret = instanceDll.SKF_EncryptInit(phKey.getValue(),bp);
		if(ret != 0) {
			System.out.println("加密初始化失败=====" + Integer.toHexString(ret));
		}
		System.out.println("----data_len---->" + data_len);
		ret = instanceDll.SKF_Encrypt(phKey.getValue(), data, data_len, encrypt_data, pulEncrypedLen);
		if(ret != 0) {
			System.out.println("加密失败=====" + Integer.toHexString(ret));
		}
		System.out.println("----pulEncrypedLen---1->" + pulEncrypedLen.getValue());
		try {
        	Native.free(Pointer.nativeValue(encrypt_data));
        	Pointer.nativeValue(encrypt_data, 0);
        }catch(Exception ex) {
        	ex.printStackTrace();
        }
		return encrypt_data.getByteArray(0, pulEncrypedLen.getValue()); 
		 
	}
	
	public byte[] GXUSBKeyDecrypt(byte[] mdata,int pulEncrypedLen) {
		int data_len = (mdata.length - 1) * 8;
		int decrypt_data_len = data_len + 1024;
		Pointer decrypt_data = new Memory(1024);
		IntByReference pulDecrypedLen = new IntByReference();
		pulDecrypedLen.setValue(decrypt_data_len);
		int ret = 0;
		//解密
		ret = instanceDll.SKF_DecryptInit(phKey.getValue(),bp);
		if(ret != 0) {
			System.out.println("解密初始化失败=====" + Integer.toHexString(ret));
		} 
		
		ret = instanceDll.SKF_Decrypt(phKey.getValue(), mdata, pulEncrypedLen, decrypt_data, pulDecrypedLen);
		if(ret != 0) {
			System.out.println("加密失败=====" + Integer.toHexString(ret));
		}
		try {
        	Native.free(Pointer.nativeValue(decrypt_data));
        	Pointer.nativeValue(decrypt_data, 0);
        }catch(Exception ex) {
        	ex.printStackTrace();
        }
		return decrypt_data.getByteArray(0, pulDecrypedLen.getValue()); 
		 
	}*/
}
